/*****************************************************************************
 * File:  CASTHelper.cs Class: CASTHelper 
 * by:    Phil Allison
 * Purpose: Intented to help format and remove errors in data conversion.
 * 
 * copyright (c) 2001-2012, Phil Allison. Under the MIT License http://www.opensource.org/licenses/mit-license.php  
 * Feel free to reuse and modify this code as long as credit is given to the original author.
 * Modified code must be noted in this section.
 * 
 * List of Functions:
 * =================
 * Date    - Return a DateTime object from the input object.
 * DateISO - return a YYYY-MM-DD formatted Date string.
 * Boolean - convert input to a true/false. 'Y', 'yes', 1, all get converted to true.
 * Integer - Convert input to integer value.
 * Decimal - Convert input to decimal value.
 * isNumeric   - Determines if a string is numeric. 
*****************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace sgsBase
{
	public class CASTHelper
	{
        /// <summary>
        /// Convert input to DateTime
        /// </summary>
        /// <param name="dt">datetime in a string format</param>
        /// <returns>DateTime</returns>
		public static DateTime Date(string inp, bool inpRemoveTime = false)
		{
			DateTime dt = DateTime.MinValue;
			if (inp == "")
				return dt;
			try
			{
				dt = DateTime.Parse(inp);
			}
			catch
			{
			}

			if (inpRemoveTime)
				dt = Date(dt.ToShortDateString());

			return dt;
		}

		/// <summary>
		/// Takes a generic argument for datetime
		/// </summary>
		/// <param name="dt"></param>
		/// <returns></returns>
		public static DateTime Date(object dt, bool inpRemoveTime = false)
		{
			return Date(dt.ToString(), inpRemoveTime);
		}

        /// <summary>
        /// Convert input to yyyy-mm-dd format
        /// </summary>
        /// <param name="dt"></param>
        /// <returns>string in 'yyyy-mm-dd' format</returns>
        public static string DateISO(DateTime dt, bool dateOnly=true)
        {
            //string ret = "";
			if (dateOnly)
				return dt.ToString("yyyy-MM-dd");

			return dt.ToString ( "s", System.Globalization.CultureInfo.InvariantCulture );
            //ret = dt.Year.ToString() + "-" + dt.Month.ToString("00") + "-" + dt.Day.ToString("00");
            //return ret;
        }
		public static string DateISO(object inp)
		{
			DateTime dt = Date(inp);
			return DateISO(dt);
		}


		/// <summary>
		/// Convert to Boolean 
		/// </summary>
		/// <param name="inp"></param>
		/// <returns></returns>
		/// This function will convert any standard value that would be a 1 to true
		/// standard values for true are: 1, true, yes
		public static bool Boolean(object inp)
		{
			return Boolean(inp.ToString());
		}
		public static bool Boolean(string inp)
		{
			if (inp == "1" || inp.ToLower() == "true" || inp.ToLower() == "yes")
				return true;

			return false;
		}
		public static bool Boolean(int inp)
		{
			if (inp != 0)
				return true;

			return false;
		}

		/// <summary>
		/// returns the Hour from a given string
		/// </summary>
		/// <param name="inp"></param>
		/// <returns></returns>
		/// This function looks for the first approximation it can make of what the hour might be. 
		public static int Hour(object inp)
		{
			string inpp = inp.ToString();

			string sep = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator;
			if (inpp.IndexOf(sep) > 0)
				inpp = inpp.Substring(0, inpp.IndexOf(sep));

			return Integer(inpp);
		}

		/// <summary>
		/// returns the time in a fractional setting. 
		/// </summary>
		/// <param name="inp"></param>
		/// <returns></returns>
		/// For example, if the time is 3:15 am, this function returns 3.25
		public static decimal Time(object inp)
		{
			string tmp = inp.ToString();
			decimal inpp;

			string sep = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator;
			if (tmp.IndexOf(sep) > 0)
			{
				inpp = Integer(tmp.Substring(0, tmp.IndexOf(sep)));
				inpp += (decimal)(Decimal(tmp.Substring(tmp.IndexOf(sep) + 1)) / 60) ;
			}
			else
				inpp = Integer(tmp);

			return inpp;
		}
        /// <summary>
		/// Convert input value into integer format
		/// </summary>
		/// <param name="inp">The value being converted to integer</param>
		/// <returns></returns>
		/// <remarks>Phil Allison</remarks>
		public static int Integer(bool inp)
		{
			if (inp)
				return 1;
			return 0;
		}
        public static int Integer(string inp)
        {
            int ret = 0;
			if (inp == null || inp == "")
                return ret;

			inp = inp.ToLower();

			if (inp == "true" || inp == "yes" || inp == "y" || inp == "t")
				return 1;

			if (inp == "false" || inp == "no" || inp == "n" || inp == "f")
				return 0;

			string sep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
			inp = stripNonNumeric(inp);
			if (inp.IndexOf(sep) > -1)
				inp = inp.Substring(0, inp.IndexOf(sep));

            try
            {
				if (inp != "NaN" && isNumeric(inp))
					ret = Convert.ToInt32(inp);
            }
            catch(Exception ex)
            {
				Email.SendError("Conversion Error", "Error converting " + inp + " to Integer", ex);
            }
            return ret;
        }
		public static int Integer(object inp)
		{
			int ret = 0;
			if (inp == null)
				return ret;

			return Integer(inp.ToString());
		}
		public static int Integer(decimal inp)
		{
			int outp = (int)inp;
			
			return outp;
		}

		/// <summary>
		/// Convert input value into long format
		/// </summary>
		/// <param name="inp">The value being converted to integer</param>
		/// <returns></returns>
		/// <remarks>Phil Allison</remarks>
		public static long Long(bool inp)
		{
			if (inp)
				return 1;
			return 0;
		}
		public static long Long(string inp)
		{
			long ret = 0;
			if (inp == "")
				return ret;

			string sep = System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
			inp = stripNonNumeric(inp);
			if (inp.IndexOf(sep) > 0)
				inp = inp.Substring(0, inp.IndexOf(sep));
			try
			{
				if (inp != "NaN" && isNumeric(inp))
					ret = Convert.ToInt64(inp);
			}
			catch (Exception ex)
			{
				Email.SendError("Conversion Error", "Error converting " + inp + " to Integer", ex);
			}
			return ret;
		}
		public static long Long(object inp)
		{
			long ret = 0;
			if (inp == null)
				return ret;

			return Long(inp.ToString());
		}
		public static long Long(decimal inp)
		{
			long outp = (long)inp;

			return outp;
		}

		/// <summary>
		/// Convert Value to Double
		/// </summary>
		/// 
		public static double Double(int inp)
		{
			return Convert.ToDouble(inp);
		}
		public static double Double(decimal inp)
		{
			return Convert.ToDouble(inp);
		}
		public static double Double(object inp)
		{
			return Double(inp.ToString());
		}
		public static double Double(string inp)
		{
			if (inp == "")
				return 0;

			if (inp.Contains("-")) // then a fraction may be present
			{
				string[] ra = inp.Split('-');
				if (ra.Length > 1 && ra[1].Contains("/"))
				{
					string[] frac = ra[1].Split('/');
					double top = Convert.ToDouble(frac[0]);
					double bot = Convert.ToDouble(frac[1]);
					double cvt = top / bot;
					return Convert.ToDouble(ra[0]) + cvt;
				}
			}
			inp = stripNonNumeric(inp);
			if (isNumeric(inp))
				return Convert.ToDouble(inp);

			return 0;
		}

		public static float Float(object inp)
		{
			if (isNumeric(inp))
			{
				try
				{
					decimal inp2 = Decimal(inp);
					return (float)inp2;
				}
				catch
				{
				}
			}

			return 0;
		}

		private static string stripNonNumeric(object inp)
		{
			return stripNonNumeric(inp.ToString());
		}
		private static string stripNonNumeric(string inp)
		{
			if (inp == null)
				return "";
			inp = inp.Replace("$", "").Replace(",", "").Replace("(","-").Replace(")","").Trim();
			inp = inp.Replace("+", "");
			
			return inp;
		}
		/// <summary>
		/// Convert Value to Decimal
		/// </summary>
		/// <param name="inp"></param>
		/// <returns>Decimal value. 0 if input could not be converted</returns>
		/// <remarks>Phil Allison</remarks>
		public static decimal Decimal(int inp)
		{
			return Convert.ToDecimal(inp);
		}
		public static decimal Decimal(string inp)
		{
			decimal ret = 0;
			if (inp == "")
				return ret;

			inp = stripNonNumeric(inp); 
			try
			{
				if (isNumeric(inp))
					ret = Convert.ToDecimal(inp);
			}
			catch
			{
			}
			return ret;
		}
		public static decimal Decimal(object inp)
		{
			return Decimal(inp.ToString());
		}

		public static decimal Decimal(object inp, int decimals)
		{
			decimal ret = 0;

			try
			{
				ret = Decimal(inp);
				ret = Math.Round(ret, decimals);
			}
			catch
			{
			}
			return ret;
		}		
		
		/// <summary>
		/// Determines if the values of the given string is of the given number style. 
		/// </summary>
		/// <param name="val"></param>
		/// <param name="NumberStyle"></param>
		/// <returns></returns>
		public static bool isNumeric(string val, System.Globalization.NumberStyles NumberStyle)
		{
			Double result;
			return System.Double.TryParse(val, NumberStyle, System.Globalization.CultureInfo.CurrentCulture, out result);
		}
		public static bool isNumeric(object val)
		{
			return isNumeric(val.ToString(), System.Globalization.NumberStyles.Number);
		}
		public static bool isNumeric(string val)
		{
			return isNumeric(val, System.Globalization.NumberStyles.Number);
		}
		public static bool isNumeric(char val)
		{
			if (char.GetNumericValue(val) > -1)
				return true;
			return false;
			//string s = char.ToString(val);
			//return isNumeric(s);
		}
		public static bool isMoney(string val)
		{
			return isNumeric(val, System.Globalization.NumberStyles.Currency);
		}

		/// <summary>
		/// Return the value of the bit flag at a specific location 
		/// </summary>
		/// <param name="location"></param>
		/// <returns></returns>
		/// Example: to get the value of the bit at position 7, you are looking for 1000000.
		/// This function returns the integer value of that bit; 2^(7-1)
		public static int BitFlag(int location)
		{
			return (int)Math.Pow(2,location - 1);
		}
		public static int BitFlag(string location)
		{
			return BitFlag(CASTHelper.Integer(location));
		}

		public static bool And(int val1, int val2)
		{
			return (val1 & val2) != 0;
		}

		/// <summary>
		/// Simple (really simple) encrypt. The input string of numbers must be at least 4 digits long.
		/// 1. Add 3 random digits to begin. 
		/// 2. Start at beginning of string, transpose 2 digits, insert random digit, repeat.
		/// 3. Ensure result string is same length as original by adding real digit if needed.
		/// 4. Add 3 random digits.
		/// </summary>
		/// <param name="inp"></param>
		/// <returns></returns>
		public static string simpleNumberEncrypt(string inp)
		{
			inp = inp.Trim();  // must remove any spaces first!
			string ret = "";
			int ndx = 0;
			string leftOver = "";
			Random rdm = new Random();

			if (inp.Length < 4)
				return inp;

			if ((inp.Length % 2) != 0)
			{
				leftOver = inp.Substring(inp.Length - 1, 1);
				inp = inp.Substring(0, inp.Length - 1);
			}

			ret += rdm.Next(9).ToString().Substring(0, 1);
			ret += rdm.Next(9).ToString().Substring(0, 1);
			ret += rdm.Next(9).ToString().Substring(0, 1);
			
			while (ndx < inp.Length - 1)
			{
				ret += inp[ndx + 1].ToString() + inp[ndx].ToString();
				ret += rdm.Next(9).ToString().Substring(0, 1);
				ndx += 2;
			}
			ret += leftOver;
			ret += rdm.Next(9).ToString().Substring(0, 1);
			ret += rdm.Next(9).ToString().Substring(0, 1);
			ret += rdm.Next(9).ToString().Substring(0, 1);

			return ret;
		}

		public static string simpleNumberDecrypt(string inp)
		{
			inp = inp.Trim();  // must remove any spaces first!
			string ret = "";
			string s = "";
			int ndx = 0;

			if (inp.Length < 4)
				return inp;

			inp = inp.Substring(3, inp.Length - 6); // strip first and last 3 digits off
			ndx = 0;
			while (ndx < inp.Length)
			{
				if (((ndx+1) % 3 != 0))
					s += inp.Substring(ndx,1);
				ndx++;
			}

			for (ndx = 0; ndx < s.Length; ndx += 2)
			{
				ret += (ndx < s.Length - 1) ? (s[ndx + 1].ToString() + s[ndx].ToString()) : s[ndx].ToString();
			}

			return ret;

		}

		public static int OrderNo(object inp)
		{
			long ret = OrdernoRelno(inp);
			return CASTHelper.Integer(ret / 1000);
		}

		public static int ReleaseNo(object inp)
		{
			long ret = OrdernoRelno(inp);
			return CASTHelper.Integer(ret - ((ret / 1000) * 1000));
		}
		public static long OrdernoRelno(object inp)
		{
			string cvt = inp.ToString();
			long ret = 0;
			cvt = cvt.Replace("-", "").Trim();
			if (cvt.Length == 6) // current length of order #
			{
				ret = CASTHelper.Long(cvt) * 1000;
			}
			else if (cvt.Length > 9)
			{
				cvt = cvt.Substring(0, 9);
				ret = CASTHelper.Long(cvt);
			}
			else
				ret = CASTHelper.Long(cvt);
			return ret;
		}

		public static int RoundUp(object inp)
		{
			double db = CASTHelper.Double(inp);
			return (int)Math.Ceiling(db);
		}
	}
}
